package com.qyer.commons.test.concurrent;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Lists;
import com.qyer.commons.concurrent.ArrayListBulk;
import com.qyer.commons.concurrent.PoisonPill;
import com.qyer.commons.concurrent.assemblingline.AbstractHandler;
import com.qyer.commons.concurrent.assemblingline.AssemblerGroup;
import com.qyer.commons.concurrent.assemblingline.AssemblingLine;
import com.qyer.commons.concurrent.assemblingline.HandleException;
import com.qyer.commons.concurrent.assemblingline.ResultWriter;
import com.qyer.commons.concurrent.assemblingline.StatisticContext;
import com.qyer.commons.mc.converter.Converter;
import com.qyer.commons.utils.JsonOperator;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * User: Z J Wu Date: 2016/06/02 Time: 17:30 Package: com.qyer.commons.concurrent
 */
public class MockCDBMember implements PoisonPill<MockCDBMember>, Comparable<MockCDBMember> {

  public static class String2CDBMemberConverter extends Converter<String, MockCDBMember> {

    @Override
    public MockCDBMember convert(String s) throws Exception {
      if (StringUtils.isBlank(s)) {
        return null;
      }
      return MockCDBMember.createBasicCDBMember(Integer.parseInt(s));
    }
  }

  public static class EmailQueryHandler extends AbstractHandler<ArrayListBulk<MockCDBMember>,
    ArrayListBulk<MockCDBMember>> {

    public EmailQueryHandler(StatisticContext context) {
      super(context);
    }

    @Override
    public ArrayListBulk<MockCDBMember> handle(ArrayListBulk<MockCDBMember> bulk) throws
      HandleException {
      if (bulk == null) {
        return null;
      }
      for (MockCDBMember mockCDBMember : bulk.getList()) {
        mockCDBMember.setEmail(RandomStringUtils.randomAlphabetic(5) + "@qyer.com");
      }
      long sleep = RandomUtils.nextLong(100, 401);
      try {
        TimeUnit.MILLISECONDS.sleep(sleep);
      } catch (InterruptedException e) {
        throw new HandleException(e);
      }
      return bulk;
    }
  }

  public static class DeviceIdQueryHandler extends AbstractHandler<ArrayListBulk<MockCDBMember>,
    ArrayListBulk<MockCDBMember>> {

    public DeviceIdQueryHandler(StatisticContext context) {
      super(context);
    }

    @Override
    public ArrayListBulk<MockCDBMember> handle(ArrayListBulk<MockCDBMember> bulk) throws
      HandleException {
      if (bulk == null) {
        return null;
      }
      for (MockCDBMember mockCDBMember : bulk.getList()) {
        int cnt = RandomUtils.nextInt(0, 4);
        List<String> devices = Lists.newArrayListWithCapacity(cnt);
        for (int i = 0; i < cnt; i++) {
          devices.add(RandomStringUtils.randomAlphabetic(16));
        }
        mockCDBMember.setDevices(devices);
      }
      long sleep = RandomUtils.nextLong(100, 201);
      try {
        TimeUnit.MILLISECONDS.sleep(sleep);
      } catch (InterruptedException e) {
        throw new HandleException(e);
      }
      return bulk;
    }
  }

  @JsonProperty("uid")
  private int id;
  @JsonProperty("email")
  private String email;
  @JsonProperty("devices")
  private List<String> devices;

  private MockCDBMember() {
    this.id = 0;
  }

  private MockCDBMember(int id) {
    this.id = id;
  }

  public static MockCDBMember createBasicCDBMember(int id) {
    if (id <= 0) {
      throw new IllegalArgumentException("id cannot <= 0");
    }
    return new MockCDBMember(id);
  }

  @Override
  @JsonIgnore
  public boolean isPill() {
    return this.id == 0;
  }

  @Override
  public MockCDBMember createPill() {
    return new MockCDBMember();
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public List<String> getDevices() {
    return devices;
  }

  public void setDevices(List<String> devices) {
    this.devices = devices;
  }

  @Override
  public String toString() {
    ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
    if (isPill()) {
      tsb.append("(PILL)");
    } else {
      tsb.append("id", id).append("email", email).append("device", devices);
    }
    return tsb.toString();
  }

  @Override
  public int compareTo(MockCDBMember o) {
    if (o == null) {
      return 1;
    }
    return this.id - o.getId();
  }

  public static void main(String[] args) throws Exception {
    System
      .setProperty("test.db.main.properties.location", "/Users/WuZijing/dsp/db.main.properties");
    System
      .setProperty("test.db.mongo.properties.location", "/Users/WuZijing/dsp/db.mongo.properties");

    String in = "/Users/WuZijing/securecrt_rzsz/query_result.csv", out = in + ".result";
    MockCDBMember.String2CDBMemberConverter converter = new MockCDBMember
      .String2CDBMemberConverter();

    StatisticContext context = new StatisticContext();
    int emailBulkSize = 50, deviceBulkSize = 30;
    MockCDBMember.EmailQueryHandler emailQuerier = new MockCDBMember.EmailQueryHandler(context);
    MockCDBMember.DeviceIdQueryHandler deviceIdQuerier = new MockCDBMember.DeviceIdQueryHandler(
      context);
    ResultWriter resultWriter = new ResultWriter(context, out);

    AssemblingLine<MockCDBMember> builder = new AssemblingLine<>(context, 20);
    builder.setFileDataGenerator("FileDataGenerator", in, converter);
    builder.setFileSummarizer("FileOutputSummarizer", resultWriter);
    builder.addAssemblerGroup("EmailAssembler", 20, emailQuerier, emailBulkSize)
           .addAssemblerGroup("DeviceAssembler", 10, deviceIdQuerier, deviceBulkSize);
    builder.connect();

    System.out.println(builder.getRawDataGenerator());
    for (AssemblerGroup<MockCDBMember> group : builder.getAssemblerGroups()) {
      System.out.println(group);
    }
    System.out.println(builder.getSummarizer());
    System.out.println(JsonOperator.getInstance().toJson(builder.start()));
  }
}
